package com.matrix.order.domain.service;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.matrix.api.order.dto.OrderItemDTO;
import com.matrix.api.product.vo.ProductVO;
import com.matrix.api.product.vo.SpecOptionVO;
import com.matrix.common.exception.BusinessException;
import com.matrix.order.domain.model.Order;
import com.matrix.order.domain.model.OrderItem;
import com.matrix.order.domain.model.OrderPayment;
import com.matrix.order.infrastructure.gateway.acl.ProductAcl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 有点甜
 * @since 2025/8/2
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderDomainService {

    private final ProductAcl productAcl;
    private final Snowflake snowflake = IdUtil.getSnowflake();

    public OrderPayment addDishesToOrder(Order order, Long userId, List<OrderItemDTO> itemsToAdd) {
        if (!order.getUserId().equals(userId)) {
            throw new BusinessException("无权操作此订单");
        }
        if (!order.getStatus().canAddOrCancelDish()) {
            throw new BusinessException(order.getStatus().getCannotAddOrCancelDishMessage());
        }

        List<Long> productIds = itemsToAdd.stream().map(OrderItemDTO::getProductId).distinct().toList();
        Map<Long, ProductVO> productMap = productAcl.getProductsByIds(productIds);
        List<OrderItem> newItems = itemsToAdd.stream()
                .map(itemDTO -> buildNewOrderItem(order.getId(), itemDTO, productMap))
                .toList();

        BigDecimal addedAmount = newItems.stream()
                .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        if (addedAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("加菜金额必须大于0");
        }

        OrderPayment payment = new OrderPayment();
        payment.setOrderId(order.getId());
        payment.setPaymentNo("P" + snowflake.nextId());
        payment.setAmount(addedAmount);
        payment.setStatus(0);
        payment.setDescription("加菜单");
        payment.setCreateTime(LocalDateTime.now());
        order.addPayment(payment);

        for (OrderItem item : newItems) {
            item.setPaymentId(payment.getId());
        }

        order.addNewItems(newItems);

        return payment;
    }

    private OrderItem buildNewOrderItem(Long orderId, OrderItemDTO itemDTO, Map<Long, ProductVO> productMap) {
        ProductVO product = productMap.get(itemDTO.getProductId());
        if (product == null) {
            throw new BusinessException("部分菜品已下架或不存在,请返回菜单刷新");
        }
        if (product.getStatus() != 1) {
            throw new BusinessException("菜品 [" + product.getName() + "] 已禁售");
        }

        BigDecimal itemPrice = product.getBasePrice();
        StringBuilder specsDesc = new StringBuilder();

        if (!CollectionUtils.isEmpty(itemDTO.getSpecOptionIds())) {
            Map<Long, SpecOptionVO> optionMap = product.getSpecs().stream()
                    .flatMap(group -> group.getOptions().stream())
                    .collect(Collectors.toMap(SpecOptionVO::getId, Function.identity()));

            for (Long optionId : itemDTO.getSpecOptionIds()) {
                SpecOptionVO option = optionMap.get(optionId);
                if (option != null) {
                    itemPrice = itemPrice.add(option.getPriceModifier());
                    if (!specsDesc.isEmpty()) {
                        specsDesc.append(",");
                    }
                    specsDesc.append(option.getName());
                } else {
                    log.warn("Order creation warning: SpecOptionId {} not found for ProductId {}.", optionId, product.getId());
                }
            }
        }

        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(orderId);
        orderItem.setProductId(product.getId());
        orderItem.setProductName(product.getName());
        orderItem.setProductImageUrl(product.getImageUrl());
        orderItem.setSpecs(specsDesc.toString());
        orderItem.setPrice(itemPrice);
        orderItem.setQuantity(itemDTO.getQuantity());
        orderItem.setAdded(true);
        orderItem.setStatus(0);
        return orderItem;
    }
}
